home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / New System Software Extensions / SCSI Manager 4.3f1 / Example code / SampleSCSI.c
Encoding:
C/C++ Source or Header  |  1993-04-28  |  5.2 KB  |  203 lines  |  [TEXT/MPS ]

  1. /****************************************************************
  2. **
  3. ** Example.c
  4. **
  5. **    Copyright:    © 1992 by Apple Computer, Inc., all rights reserved.
  6. **
  7. ** This code snippet contains an entire application which uses 
  8. ** the Asynchronous SCSI Manager to make an asynchronous read 
  9. ** of block zero of a drive at SCSI ID 0.  It is intended as 
  10. ** example code only and not a basis for developing a driver or
  11. ** application which uses the Asynchronous SCSI Manager.
  12. **
  13. ****************************************************************/
  14.  
  15. #include <scsi.h>
  16. #include <types.h>
  17. #include <stdio.h>
  18. #include <memory.h>
  19.  
  20. #include <ACAM.h>
  21.  
  22. /* We will move this into Traps.h eventually */
  23. #define _SCSIAtomic 0xA089
  24.  
  25. /* Prototypes */
  26. OSErr ReadItt( DeviceIdent, ulong, ushort, Ptr );
  27.  
  28. /* Constants */
  29. #define AUTOSENSE_SIZE    12
  30.  
  31. /* Globals */
  32. SCSI_IO *     scPB = 0;
  33. Ptr            SenseBuffer = nil;
  34. Boolean        working = true;
  35.  
  36.  
  37. main() 
  38. {
  39.     char                buffer[0x200];    /* space to read block into */
  40.     DeviceIdent            device;            /* device to read from */
  41.     SCSIBusInquiryPB    inqPB;            /* Info about the scsi bus */
  42.     
  43.     device.bus = 0;
  44.     device.targetID = 0;
  45.     device.LUN = 0;
  46.  
  47. /* Create and init a SCSI param block for the ReadItt function */
  48.  
  49.     /* First, get the size of a SCSI_IO for this bus */
  50.     inqPB.scsiDevice = device;
  51.     inqPB.scsiFlags = 0;
  52.     inqPB.scsiFunctionCode = SCSIBusInquiry;
  53.     inqPB.scsiCompletion = nil;
  54.     inqPB.scsiPBLength = sizeof(SCSIBusInquiryPB);
  55.     
  56.     /* BusInquiry is always synchronous */
  57.     SCSIAction( (SCSI_PB *) &inqPB );
  58.  
  59.     /* Then, allocate a block big enough */
  60.     
  61.     if( (scPB = (SCSI_IO *)NewPtrClear(inqPB.scsiIOpbSize)) == nil )
  62.         return(1);
  63.         
  64.     scPB->scsiPBLength = inqPB.scsiIOpbSize;
  65.  
  66.     /* Allocate a block for Request Sense data */
  67.     
  68.     if( (SenseBuffer = NewPtrClear(AUTOSENSE_SIZE)) == nil )
  69.         return(1);
  70.     
  71. /* Read block 0 of SCSI ID 0 on Bus 0 */    
  72.  
  73.     if( ReadItt( device, 0, 1, buffer ) )
  74.     {
  75.         DebugStr("\pBad Parameters");
  76.         working = false;    /* the completion routine isn't called */
  77.     }
  78.     
  79. /* SyncWait until we are done. */
  80.     /*
  81.     ** !!! DANGER WILL ROBINSON !!!
  82.     **
  83.     ** Don't do this in a driver!  If you do this (SyncWait) when
  84.     ** your driver is at a non-zero interrupt level you will wait a
  85.     ** long time.  The SCSI Manager needs interrrupts to get its work 
  86.     ** done.  If you are a driver and get a synchronous call (to  
  87.     ** service a VM page fault for instance) you should either 
  88.     ** make an explicit synchronous call to the SCSI Manager - or 
  89.     ** make an async one and RTS to the Device Manager.  The Device
  90.     ** Mgr is aware of this problem and will do the necessary polling
  91.     ** for interrupts.
  92.     **
  93.     */
  94.     while( working )
  95.         ;
  96. }
  97.  
  98.  
  99. pascal void
  100. CompFunc( SCSI_IO *ioPB)
  101. {
  102.     /*
  103.     ** Like, cool man - we're done.
  104.     **
  105.     ** We should inform the caller that the request completed.
  106.     ** In a disk driver that would mean calling/jmping to IODone.
  107.     **
  108.     ** We should also do error handling here
  109.     **
  110.     ** Note that this routine could/will be called at interrupt time!
  111.     ** 
  112.     */
  113.     
  114.     /*
  115.     ** Note the use of globals (working) - the SCSI Mgr sets up A5 to 
  116.     ** what it was when the SCSIAction call was made.
  117.     */
  118.     working = false;    
  119.     
  120.     /*
  121.     ** A quick word about error handling.  As with the file system,
  122.     ** synchronous requests at interrupt time are to be avoided.  This 
  123.     ** means bad block re-mapping etc. will need to be done with an 
  124.     ** intelligent completion routine which can maintain its 
  125.     ** context across several transactions.
  126.     */
  127.     if( ioPB->scsiResult != noErr )
  128.         DebugStr("\pYikes!");
  129. }
  130.  
  131.  
  132. /* ReadItt
  133. ** This function performs an asynchronous extended (10 byte) SCSI 
  134. ** read command to an arbitrary target. If the SCSIAction trap 
  135. ** returns an error then the parameter block was invalid and the  
  136. ** transaction was NEVER— this means that the completion routine
  137. ** will NOT get called.
  138. */
  139.  
  140. OSErr
  141. ReadItt(
  142.     DeviceIdent device,
  143.     ulong block,
  144.     ushort numblks,
  145.     Ptr buffer)
  146. {
  147.     uchar *cmd;
  148.     
  149.     /*
  150.     ** Please note that we are not passing Ptrs to local variables to 
  151.     ** the SCSI Manager.  Since the transaction is not necessarily 
  152.     ** finished when this function completes we cannot be assured 
  153.     ** that variables in our local stack frame will still exist when 
  154.     ** they are needed.
  155.     */
  156.     
  157.     cmd = (uchar *)&scPB->scsiCDB;
  158.  
  159.     /* Note that LUNs are dealt with in the Identify Message
  160.         in SCSI2.  If your device needs it, you can still stuff
  161.         it into the CDB. */
  162.         
  163.     cmd[0] = 0x28;    /* Extended Read Command */
  164.     
  165.     cmd[1] = 0;
  166.     
  167.     cmd[2] = block>>24;    
  168.     cmd[3] = block>>16;
  169.     cmd[4] = block>>8;
  170.     cmd[5] = block;
  171.  
  172.     cmd[6] = 0;                    /* reserved */
  173.     
  174.     cmd[7] = numblks>>8;
  175.     cmd[8] = numblks;
  176.     cmd[9] = 0;                    /* reserved */
  177.  
  178.     scPB->scsiCDBLength = 10;
  179.  
  180.     scPB->scsiFlags = (scsiSIMQNoFreeze | scsiDirectionIn | scsiDoDisconnect);
  181.     scPB->scsiDevice = device;    
  182.     scPB->scsiCompletion = CompFunc;        /* do it asynchronously */
  183.     scPB->scsiTimeout = 0;                /* no timeout for complete xaction */
  184.         
  185.     scPB->scsiDataPtr = buffer;
  186.     scPB->scsiDataLength = numblks << 9;        /* Assumes 512 bytes/sector */
  187.     scPB->scsiDataType = scsiDataBuffer;
  188.     scPB->scsiTransferType = scsiTransferBlind;
  189.     
  190.     scPB->scsiHandshake[0] = 1;
  191.     scPB->scsiHandshake[1] = 511;
  192.     scPB->scsiHandshake[2] = 0;
  193.     
  194.     scPB->scsiSensePtr = SenseBuffer;    /* Autosense enabled by default - supply bfr */
  195.     scPB->scsiSenseLength = AUTOSENSE_SIZE;
  196.     
  197.     scPB->scsiIOFlags = 0; 
  198.     
  199.     scPB->scsiFunctionCode = SCSIExecIO;
  200.     return( SCSIAction( (SCSI_PB *)scPB) );
  201. }
  202.  
  203.